﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;
using System.IO;
using Utils;
using System.ComponentModel.Design;
using System.Diagnostics;

namespace CefSharpWinformDemo
{
    public partial class BrowserCtrl : UserControl, IDisposable
    {
        #region 外部方法
        /*
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
        [DllImport("user32.dll", SetLastError = true)]
        public static extern int MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool BRePaint);
        [DllImport("user32.dll", SetLastError = true)]
        public static extern int CloseWindow(IntPtr hWnd);
        [DllImport("User32.dll", EntryPoint = "GetWindowText")]
        private static extern int GetWindowText(IntPtr hwnd, StringBuilder lpString, int nMaxCount);
        */
        #endregion

        #region 变量属性事件
        private static bool _isCefInited = false;

        private static object _lockObject = new object();

        private bool _firstLoad = true;

        /// <summary>
        /// 浏览器FrameLoadEnd事件
        /// </summary>
        public event EventHandler FrameLoadEnd;

        private ExtChromiumBrowser _browser;

        public ExtChromiumBrowser Browser
        {
            get
            {
                WaitUtil.Wait(() => this._browser != null && _isCefInited);

                return this._browser;
            }
        }

        private static LimitedTaskScheduler _scheduler = new LimitedTaskScheduler(2);
        #endregion

        #region 构造函数
        public BrowserCtrl()
        {
            InitializeComponent();

            lock (_lockObject)
            {
                if (!_isCefInited)
                {
                    _isCefInited = true;
                    InitCef();//初始化CefSharp
                }
            }

            _browser = new ExtChromiumBrowser(null);
            BindBrowser(_browser);
            _browser.Dock = DockStyle.Fill;
            this.Controls.Add(_browser);
        }
        #endregion

        #region BrowserCtrl_Loaded
        private void BrowserCtrl_Load(object sender, EventArgs e)
        {

        }
        #endregion

        #region Dispose 释放资源
        /// <summary>
        /// 释放资源
        /// </summary>
        public new void Dispose()
        {
            //如果有弹出窗口则先释放它
            //foreach (UIElement item in grid.Children)
            //{
            //    if (item is BrowserContainer)
            //    {
            //        (item as BrowserContainer).ClearResource();
            //    }
            //}

            _browser.ClearHandlers();
            if (_browser != null && !_browser.IsDisposed)
            {
                Task.Run(() =>
                {
                    try
                    {
                        _browser.Dispose();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                });
            }
            base.Dispose();
        }
        #endregion

        #region LoadUrl
        public void LoadUrl(string url)
        {
            if (!string.IsNullOrWhiteSpace(url))
            {
                //loadingWait.Visibility = Visibility.Visible;
                _scheduler.Run(() =>
                {
                    #region Wait
                    WaitUtil.Wait(() =>
                    {
                        if (this._browser == null) return false;
                        if (!_isCefInited) return false;
                        if (!this._browser.IsBrowserInitialized) return false;
                        return true;
                    });
                    #endregion

                    _browser.Load(url);
                });
            }
        }
        #endregion

        #region LoadRequest
        public void LoadRequest(string url, IRequest request)
        {
            if (_firstLoad)
            {
                _firstLoad = false;

                _scheduler.Run(() =>
                {
                    #region Wait
                    WaitUtil.Wait(() =>
                    {
                        if (this._browser == null) return false;
                        if (!_isCefInited) return false;
                        if (!this._browser.IsBrowserInitialized) return false;
                        return true;
                    });
                    #endregion

                    if (url != null && request != null)
                    {
                        try
                        {
                            _browser.Load(url);
                            _browser.GetMainFrame().LoadRequest(request);
                        }
                        catch (Exception ex)
                        {
                            LogUtil.Error(ex, "BrowserCtrl LoadUrl error Load URL失败");
                        }
                    }
                    else
                    {
                        this.Invoke(new Action(() =>
                        {

                        }));
                    }
                });
            }
        }
        #endregion

        #region BindBrowser
        private void BindBrowser(ExtChromiumBrowser browser)
        {
            browser.JavascriptObjectRepository.NameConverter = new MyCamelCaseJavascriptNameConverter();

            browser.IsBrowserInitializedChanged += (ss, ee) =>
            {

            };
            browser.FrameLoadStart += (ss, ee) =>
            {
                this.BeginInvoke(new Action(() =>
                {
                    (ss as ExtChromiumBrowser).Focus();
                }));
            };
            browser.FrameLoadEnd += (ss, ee) =>
            {
                this.BeginInvoke(new Action(() =>
                {

                }));
                if (FrameLoadEnd != null)
                {
                    FrameLoadEnd(null, null);
                }
            };
            browser.LoadError += (s, e) =>
            {
                this.BeginInvoke(new Action(() =>
                {

                }));
            };
        }
        #endregion

        #region 设置Header Token
        /// <summary>
        /// 设置Header Token
        /// </summary>
        public void SetHeaderToken(string token)
        {
            Browser.Token = token;
        }
        #endregion

        #region RegisterJsObject
        public void RegisterJsObject(string name, object objectToBind, BindingOptions options = null)
        {
            try
            {
                if (_browser != null)
                {
                    _browser.JavascriptObjectRepository.Register(name, objectToBind, false, BindingOptions.DefaultBinder);
                }
            }
            catch (Exception ex)
            {
                LogUtil.Error(ex, "BrowserCtrl RegisterJsObject 错误");
            }
        }
        #endregion

        #region 初始化CefSharp
        public static void InitCef()
        {
            string cefsharpFolder = "CefSharp";

            var settings = new CefSettings();
            //The location where cache data will be stored on disk. If empty an in-memory cache will be used for some features and a temporary disk cache for others.
            //HTML5 databases such as localStorage will only persist across sessions if a cache path is specified. 
            settings.CachePath = AppDomain.CurrentDomain.BaseDirectory + cefsharpFolder + "/cache"; //设置cache目录
            settings.Locale = "zh-CN"; //设置语言为中文

            settings.MultiThreadedMessageLoop = true;
            CefSharpSettings.FocusedNodeChangedEnabled = true;
            CefSharpSettings.LegacyJavascriptBindingEnabled = true;
            CefSharpSettings.ShutdownOnExit = true;
            CefSharpSettings.SubprocessExitIfParentProcessClosed = true;

            string logDir = AppDomain.CurrentDomain.BaseDirectory + cefsharpFolder + "/log/";
            if (!Directory.Exists(logDir))
            {
                Directory.CreateDirectory(logDir);
            }

            settings.BrowserSubprocessPath = AppDomain.CurrentDomain.BaseDirectory + cefsharpFolder + "/CefSharp.BrowserSubprocess.exe";
            settings.LogFile = logDir + DateTime.Now.ToString("yyyyMMdd") + ".log";
            settings.LocalesDirPath = AppDomain.CurrentDomain.BaseDirectory + cefsharpFolder + "/locales";
            settings.CefCommandLineArgs.Add("enable-gpu", "1");
            settings.CefCommandLineArgs.Add("enable-media-stream", "1");
            settings.CefCommandLineArgs.Add("touch-events", "1"); //触屏事件
            settings.CefCommandLineArgs.Add("ignore-gpu-blacklist", "1"); //忽略显卡黑名单
            settings.CefCommandLineArgs.Add("enable-3d-apis", "1");
            settings.CefCommandLineArgs.Add("enable-webgl", "1"); //开启WEBGL
            settings.CefCommandLineArgs.Add("enable-webgl-draft-extensions", "1");
            settings.CefCommandLineArgs.Add("allow-file-access-from-files", "1"); //本地调试WEBGL
            settings.CefCommandLineArgs.Add("disable-threaded-scrolling", "1"); //提升滚动处理性能

            //忽略https证书的问题
            settings.CefCommandLineArgs.Add("--ignore-urlfetcher-cert-requests", "1");
            settings.CefCommandLineArgs.Add("--ignore-certificate-errors", "1");
            //禁止启用同源策略安全限制，禁止后不会出现跨域问题
            settings.CefCommandLineArgs.Add("--disable-web-security", "1");

            if (!Cef.Initialize(settings, performDependencyCheck: true, browserProcessHandler: new BrowserProcessHandler()))
            {
                throw new Exception("Unable to Initialize Cef");
            }
        }
        #endregion

    }
}
